import { Flatten } from './1.属性修饰进阶'
;(function () {})()
// 并集
export type Concurrence<A, B> = A | B
type _test_Con1 = Concurrence<{ a: 'lys'; b: '123' }, { a: 'lys'; b: '123'; c: '456' }>

type _test_1 = { a: 'lys'; b: '123' }
type _test_2 = { a: 'lys'; b: '123'; c: '456' }

type _test_3 = _test_2 extends _test_1 ? 1 : 2

// 交集
export type Intersection<A, B> = A extends B ? A : never

// 差集
export type Difference<A, B> = A extends B ? never : A
// 补集
export type Complement<A, B extends A> = Difference<A, B>
// # 我们对应地实现对象属性名的版本：
// 使用更精确的对象类型描述结构
export type PlainObjectType = Record<string, any>

//属性名 并集
export type ObjectKeysConcurrence<T extends PlainObjectType, U extends PlainObjectType> = keyof T | keyof U

//属性名 交集
export type ObjectKeysIntersection<T extends PlainObjectType, U extends PlainObjectType> = Intersection<keyof T, keyof U>

type _test_3_1 = ObjectKeysIntersection<{ a: 'lys'; b: '123' }, { a: 'lys'; b: '123'; c: '456' }>
//属性名 差集
export type ObjectKeysDifference<T extends PlainObjectType, U extends PlainObjectType> = Difference<keyof T, keyof U>

//属性名 补集
export type ObjectKeysComplement<T extends U, U extends PlainObjectType> = Complement<keyof T, keyof U>

// 我们可以直接使用属性名的集合来实现对象层面的版本：
export type ObjectIntersection<T extends PlainObjectType, U extends PlainObjectType> = Pick<T, ObjectKeysIntersection<T, U>>

// ---两对象 属性的交集 的最终对象
type _test_4 = ObjectIntersection<{ a: 'lys'; b: '123' }, { a: 'lys'; b: '123'; c: '456' }>

//---两对象 属性的差集 的最终对象 (T对于 U的差集)
export type ObjectDifference<T extends PlainObjectType, U extends PlainObjectType> = Pick<T, ObjectKeysDifference<T, U>>

type _test_5 = ObjectDifference<{ a: 'lys'; b: '123'; d: '444' }, { a: 'lys'; b: '123'; c: '456' }>
// 属性名 补集
export type ObjectComplement<T extends U, U extends PlainObjectType> = Pick<T, ObjectKeysComplement<T, U>>
type _test_6 = ObjectComplement<{ a: 'lys'; b: '123'; d: '444' }, { a: 'lys'; b: '123' }>

//需要注意的是在 ObjectKeysComplement 与 ObjectComplement 中，T extends U 意味着 T 是 U 的子类型，但在属性组成的集合类型中却相反，U 的属性联合类型是 T 的属性联合类型的子类型，因为既然 T 是 U 的子类型，那很显然 T 所拥有的的属性会更多嘛。
type _test_1_1 = { a: 'lys'; b: '123' }
type _test_2_2 = { a: 'lys'; b: '123'; c: '456' }

type _test_3_3 = _test_2_2 extends _test_1_1 ? 1 : 2
//对于 T、U 两个对象，假设以 U 的同名属性类型优先，思路会是这样的：
/*
T 比 U 多的部分：T 相对于 U 的差集， ObjectDifference<T, U>

U 比 T 多的部分：U 相对于 T 的差集，ObjectDifference<U, T>

T 与 U 的交集，由于 U 的优先级更高，在交集处理中将 U 作为原集合， T 作为后传入的集合，ObjectIntersection<U, T>
*/
type Merge<T extends PlainObjectType, U extends PlainObjectType> = Flatten<ObjectDifference<T, U> & ObjectDifference<U, T> & ObjectIntersection<U, T>>

type Mergetest_1 = Merge<{ name: string; age: number }, { name: string; isHeight: boolean; age: string }>

//如果要保证原对象优先级更高，那么只需要在交集处理中将 T 视为原集合，U 作为后传入的集合：

type Assign<T extends PlainObjectType, U extends PlainObjectType> = Flatten<
  //  T 比 U 多的部分，加上 T 与 U 交集的部分(类型不同则以 T 优先级更高，再加上 U 比 T 多的部分即可
  ObjectDifference<T, U> & ObjectDifference<U, T> & ObjectIntersection<T, U>
>

type Assigntest_1 = Assign<{ name: string; age: number }, { name: string; isHeight: boolean; age: string }>

//即使用对象 U 的属性类型覆盖对象 T 中的同名属性类型，但不会将 U 独特的部分合并过来：
type Override<T extends PlainObjectType, U extends PlainObjectType> = ObjectDifference<T, U> & ObjectIntersection<U, T>

//两个对象各自独有部分组成的新集合（即从并集中剔除掉交集）就是一个很适合自己动手巩固印象的好例子。
type noInserction<T extends PlainObjectType, U extends PlainObjectType> = Flatten<ObjectDifference<T, U> & ObjectDifference<U, T>>

type noInserction_test1 = noInserction<{ name: string; age: number }, { name: string; isHeight: boolean; age: string }>
